﻿using System;
using System.Collections.Generic;
using System.IO;

using SdlDotNet.Graphics;
using SdlDotNet.Graphics.Sprites;

namespace T7G_4_Win
{
    class Cursor
    {
        /// <summary>
        /// Cursor offsets
        /// </summary>
        private readonly ushort[] offsets = { 0x50CC, 0x825D, 0x6E79, 0x50CC, 0x182F, 0x0000, 0x3B6D, 0x96D7, 0xA455, 0xA776, 0xA776 };

        /// <summary>
        /// Palette offsets
        /// </summary>
        private readonly ushort[] palOffsets = { 0xB794, 0xB794, 0xB794, 0xB794, 0xB854, 0xB794, 0xB7F4, 0xB8B4, 0xB974, 0xB914, 0xB9D4 };

        public Surface surface = null;
        private MemoryStream stream = null;

        private uint[] pal;

        private string path = Properties.Settings.Default.T7GPath;

        private byte frames = 0;

        private byte prevFrame = 255;

        /// <summary>
        /// Creates a "cursor" object
        /// </summary>
        /// <param name="cursor">Cursor number to create</param>
        public Cursor(ushort cursor)
        {
            if (cursor >= 11)
                throw new Exception("Bad cursor number");
            
            BinaryReader file = new BinaryReader(new FileStream(path + "rob.gjd", FileMode.Open, FileAccess.Read, FileShare.Read), System.Text.Encoding.UTF8);
            file.BaseStream.Seek(offsets[cursor], SeekOrigin.Begin);

            byte[] output = new byte[65535];

            ushort count = 0, offset, i, length;
            byte flags, lenMask = 0x0F, offsetLen, var_8;
            bool finished = false;
            while (!finished && file.BaseStream.Position < file.BaseStream.Length)
            {
                flags = file.ReadByte();
                for (i = 1; i <= 8; i++)
                {
                    if (file.BaseStream.Position < file.BaseStream.Length)
                    {
                        if ((flags & 1) == 1)
                        {
                            output[count] = file.ReadByte();
                            count++;
                        }
                        else
                        {
                            var_8 = file.ReadByte();
                            offsetLen = file.ReadByte();
                            if (var_8 == 0 && offsetLen == 0)
                            {
                                finished = true;
                                break;
                            }
                            length = (ushort)((offsetLen & lenMask) + 3);
                            offsetLen >>= 4;
                            offset = (ushort)((offsetLen << 8) + var_8);

                            for (; length > 0; length--, count++)
                            {
                                output[count] = output[count - offset];
                            }
                        }
                        flags >>= 1;
                    }
                }
            }

            pal = new uint[0x20];
            file.BaseStream.Seek(palOffsets[cursor], SeekOrigin.Begin);
            for (i = 0; i < 0x20; i++)
            {
                pal[i] = (uint)((0xFF0000000) + (file.ReadByte() * 65536) + (file.ReadByte() * 256) + file.ReadByte());
            }
            file.Close();
            Array.Resize<byte>(ref output, count);
            
            stream = new MemoryStream(output);
            surface = new Surface(stream.ReadByte(), stream.ReadByte(), 32);
            surface.Transparent = true;
            surface.TransparentColor = System.Drawing.Color.Black;
            frames = (byte)stream.ReadByte();
        }

        /// <summary>
        /// Called when cursor should update to next frame
        /// </summary>
        unsafe public void animate()
        {
            prevFrame++;
            prevFrame %= frames;

            int offset = surface.Width * surface.Height * prevFrame + 5;
            stream.Seek(offset, SeekOrigin.Begin);
            byte[] data = new byte[surface.Width * surface.Height];
            stream.Read(data, 0, data.Length);
            Surface tmp = new Surface(surface.Width, surface.Height, 32, 0xFF0000, 0xFF00, 0xFF, 255 << 24);
            uint* ptr = (uint*)tmp.Pixels;
            for (int i = 0; i < data.Length; i++)
            {
               *ptr = pal[data[i] % 0x20];      // Possibly a hack, but it works
               ptr++;
            }
            surface.Fill(System.Drawing.Color.Black);
            surface.Blit(tmp);
            tmp.Dispose();
        }
    }
}
